import os
import re
from typing import List, Dict, Set, Optional
from pathlib import Path


class CCodeAnalyzer:
    """C代码静态分析工具"""
    
    def __init__(self, directory: str):
        self.directory = Path(directory)
        self.c_files = []
        self.header_files = []
        self.functions = {}
        self.includes = {}
        self.macros = {}
        self.structs = {}
        
    def scan_directory(self) -> None:
        """扫描目录中的C源文件和头文件"""
        for file_path in self.directory.rglob('*'):
            if file_path.is_file():
                if file_path.suffix in ['.c', '.cpp', '.cc']:
                    self.c_files.append(file_path)
                elif file_path.suffix in ['.h', '.hpp']:
                    self.header_files.append(file_path)
    
    def extract_functions(self, content: str, file_path: str) -> Dict:
        """提取函数定义"""
        functions = {}
        # 匹配函数定义的正则表达式
        function_pattern = r'(\w+\s+)+(\w+)\s*\([^)]*\)\s*\{'
        matches = re.finditer(function_pattern, content)
        
        for match in matches:
            func_name = match.group(2)
            start_pos = match.start()
            # 查找函数结束位置
            brace_count = 0
            pos = match.end() - 1
            
            while pos < len(content):
                if content[pos] == '{':
                    brace_count += 1
                elif content[pos] == '}':
                    brace_count -= 1
                    if brace_count == 0:
                        break
                pos += 1
            
            func_body = content[start_pos:pos+1]
            functions[func_name] = {
                'signature': match.group(0)[:-1],
                'body': func_body,
                'file': file_path,
                'line': content[:start_pos].count('\n') + 1
            }
        
        return functions
    
    def extract_includes(self, content: str) -> List[str]:
        """提取#include指令"""
        include_pattern = r'#include\s*[<"](.*?)[>"]'
        return re.findall(include_pattern, content)
    
    def extract_macros(self, content: str) -> Dict:
        """提取宏定义"""
        macros = {}
        macro_pattern = r'#define\s+(\w+)(?:\([^)]*\))?\s*(.*?)(?=\n|$)'
        matches = re.finditer(macro_pattern, content)
        
        for match in matches:
            macro_name = match.group(1)
            macro_value = match.group(2).strip()
            macros[macro_name] = macro_value
        
        return macros
    
    def extract_structs(self, content: str) -> Dict:
        """提取结构体定义"""
        structs = {}
        struct_pattern = r'typedef\s+struct\s*(\w+)?\s*\{([^}]*)\}\s*(\w+)?;?'
        matches = re.finditer(struct_pattern, content, re.DOTALL)
        
        for match in matches:
            struct_name = match.group(1) or match.group(3)
            if struct_name:
                structs[struct_name] = {
                    'body': match.group(2).strip(),
                    'full_definition': match.group(0)
                }
        
        return structs
    
    def analyze_file(self, file_path: Path) -> Dict:
        """分析单个文件"""
        try:
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                content = f.read()
        except Exception as e:
            return {'error': str(e)}
        
        file_info = {
            'path': str(file_path),
            'functions': self.extract_functions(content, str(file_path)),
            'includes': self.extract_includes(content),
            'macros': self.extract_macros(content),
            'structs': self.extract_structs(content),
            'lines': len(content.splitlines())
        }
        
        return file_info
    
    def analyze_all(self) -> Dict:
        """分析所有文件"""
        self.scan_directory()
        
        analysis_result = {
            'summary': {
                'c_files_count': len(self.c_files),
                'header_files_count': len(self.header_files),
                'total_functions': 0,
                'total_structs': 0,
                'total_macros': 0
            },
            'files': {},
            'function_index': {},
            'include_graph': {}
        }
        
        # 分析所有文件
        all_files = self.c_files + self.header_files
        for file_path in all_files:
            file_info = self.analyze_file(file_path)
            analysis_result['files'][str(file_path)] = file_info
            
            # 构建函数索引
            if 'functions' in file_info:
                for func_name, func_info in file_info['functions'].items():
                    analysis_result['function_index'][func_name] = func_info
                analysis_result['summary']['total_functions'] += len(file_info['functions'])
            
            # 统计宏和结构体
            if 'macros' in file_info:
                analysis_result['summary']['total_macros'] += len(file_info['macros'])
            if 'structs' in file_info:
                analysis_result['summary']['total_structs'] += len(file_info['structs'])
            
            # 构建包含关系图
            if 'includes' in file_info:
                analysis_result['include_graph'][str(file_path)] = file_info['includes']
        
        return analysis_result
    
    def search_function(self, function_name: str) -> Optional[Dict]:
        """搜索特定函数"""
        for file_info in self.functions.values():
            if function_name in file_info.get('functions', {}):
                return file_info['functions'][function_name]
        return None
    
    def find_dependencies(self, file_path: str) -> Set[str]:
        """查找文件依赖关系"""
        dependencies = set()
        
        def _find_deps(path: str, visited: Set[str]):
            if path in visited:
                return
            visited.add(path)
            
            if path in self.includes:
                for include in self.includes[path]:
                    dependencies.add(include)
                    # 递归查找依赖
                    include_path = self._resolve_include_path(include)
                    if include_path:
                        _find_deps(include_path, visited)
        
        _find_deps(file_path, set())
        return dependencies
    
    def _resolve_include_path(self, include: str) -> Optional[str]:
        """解析include路径"""
        # 简单的路径解析，可以根据实际情况扩展
        for file_path in self.header_files:
            if file_path.name == include:
                return str(file_path)
        return None
    
    def generate_report(self, output_file: str = None) -> str:
        """生成分析报告"""
        analysis = self.analyze_all()
        
        report = f"""
C代码静态分析报告
================

文件统计:
- C源文件: {analysis['summary']['c_files_count']}
- 头文件: {analysis['summary']['header_files_count']}
- 总函数数: {analysis['summary']['total_functions']}
- 总结构体数: {analysis['summary']['total_structs']}
- 总宏定义数: {analysis['summary']['total_macros']}

函数列表:
"""
        
        for func_name, func_info in analysis['function_index'].items():
            report += f"- {func_name} (位于 {func_info['file']}:{func_info['line']})\n"
        
        if output_file:
            with open(output_file, 'w', encoding='utf-8') as f:
                f.write(report)
        
        return report


def analyze_c_code_directory(directory: str, output_report: str = None, verbose: bool = False) -> Dict:
    """
    分析指定目录中的C代码
    
    Args:
        directory: 要分析的目录路径
        output_report: 输出报告文件路径（可选）
        verbose: 是否显示详细信息
    
    Returns:
        分析结果字典
    """
    if not os.path.exists(directory):
        raise FileNotFoundError(f"目录不存在: {directory}")
    
    analyzer = CCodeAnalyzer(directory)
    result = analyzer.analyze_all()
    
    if verbose:
        print(f"分析目录: {directory}")
        print(f"找到 {result['summary']['c_files_count']} 个C文件")
        print(f"找到 {result['summary']['header_files_count']} 个头文件")
        print(f"提取 {result['summary']['total_functions']} 个函数")
        print(f"提取 {result['summary']['total_structs']} 个结构体")
        print(f"提取 {result['summary']['total_macros']} 个宏定义")
    
    if output_report:
        report = analyzer.generate_report(output_report)
        if verbose:
            print(f"报告已保存到: {output_report}")
    
    return result
